<?php
/**
 * 素材制作工具，客户管理共享商品
 *
 * Author: lyun
 * Date: 2018/9/21
 * Created by Panxsoft.
 */


namespace App\Http\Controllers\PC\Customer;

use App\Http\Controllers\ApiController;
use App\Http\Requests\PC\Customer\CustomerProductsRequest;
use App\Http\Requests\PC\Customer\PatchProductsAssetRequest;
use App\Http\Requests\PC\Customer\ShareProductCreateRequest;
use App\Http\Requests\PC\Customer\ShareProductIndexRequest;
use App\Models\Customer\Asset;
use App\Models\Customer\Customer;
use App\Models\Customer\Language;
use App\Models\Panx\Brand;
use App\Models\Panx\BrandSeries;
use App\Models\Panx\Category;
use App\Models\Panx\Product;
use App\Services\Product\CopyProductService;
use App\Services\Repositories\Product\ShareProductRepository;
use App\Services\Utils\PanxCollection;
use App\Services\Utils\Transaction;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Collection as BaseCollection;

class ShareProductController extends ApiController
{
    const ROUTES = [
        'index'                 => 'api.pc.share-product',
        'patchProductsAsset'    => 'api.pc.share-product.index.products.asset',
    ];

    /**
     * 返回虚拟客户共享商品列表
     * @test
     *
     * @param ShareProductIndexRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function index(ShareProductIndexRequest $request)
    {
        $customer = $this->checkIsNotVirtualCustomer($request->customer_id);

        $customer_categories = $this->getHasAssetCustomerCategories($customer);
        $customer_category_ids = $customer_categories->modelKeys();

        $providers = Customer::virtualProviders();

        /** @var LengthAwarePaginator $products */
        $products = (new Product)
            ->filterOnShelf()
            ->has('asset')
            ->filterCustomersOwn($providers->modelKeys()) // 过滤出正常的虚拟供应商商品
            ->filterCategoryHasAsset(Category::HAS_ASSET)   // 过滤商品的类型：化妆品
            ->whereIn('category_id', $customer_category_ids)  // 过滤客户有的分类
            ->filterCategory($request->category_id) // 过滤前端请求的分类
            ->columnsKeywordOrLike(['title', 'name'], $request->keyword)
            ->filterBrand($request->brand_id)
            ->filterBrandSeries($request->brand_series_id)
            ->with(['colorThumbImage', 'thumbImage', 'asset'])
            ->latest('ref_count')
            ->paginate($request->per_page ?: 15);

        (new PanxCollection($products->getCollection()))
            ->eachAppend([
                'color_thumb_url', 'thumb_url', 'asset_code'
            ])
            ->makeHidden([
                'colorThumbImage', 'thumbImage'
            ]);

        return $this->response(compact('products'));
    }

    /**
     *  返回当前登录客户的开通类别信息和虚拟客户的品牌信息
     *
     * @param ShareProductCreateRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \App\Exceptions\ApiAbstractException
     */
    public function create(ShareProductCreateRequest $request)
    {
        $customer = $this->checkIsNotVirtualCustomer($request->customer_id);

        $customer_categories = $this->getHasAssetCustomerCategories($customer);

        $group_brands_with_series = $this->groupVirtualBrandsByCategory();

        $group_customer_categories = $this->groupCategoriesByBrandsWithSeries($customer_categories, $group_brands_with_series);

        $group_customer_categories = $this->foreachAssembleData($group_customer_categories);

//        $group_brands = $this->getGroupBrandsWithBrandSeries();

        return $this->response(compact('group_customer_categories'));
    }

    /**
     * @deprecated
     * @see \App\Http\Controllers\PC\CustomerStore\AssetController::store
     * @see \App\Http\Controllers\PC\CustomerStore\ProductController::patchesAsset
     * 复制虚拟客户的素材，批量更新客户商品的asset_id
     * @test
     *
     * @param PatchProductsAssetRequest $request
     *
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function patchProductsAsset(PatchProductsAssetRequest $request)
    {
        $customer = $this->checkIsNotVirtualCustomer($request->customer_id);
        $customer_id = $customer->id;

        $asset = (new Asset)->find($request->asset_id);
            $this->checkItemExist($asset);

        $product_ids = $request->product_ids;

        $updated = Transaction::handle(function() use($customer_id, $asset, $product_ids){

            $customer_asset = (new CopyProductService)->copyAsset($asset, $customer_id);

            $updated = (new Product)->where('customer_id', $customer_id)
                ->whereIn('id', $product_ids)
                ->update(['asset_id'=>$customer_asset->id]);

            return $updated;
        });

        return $this->response(compact('updated'));
    }

    /**
     * @param Customer $customer
     * @return Collection
     */
    private function getHasAssetCustomerCategories(Customer $customer)
    {
        $language_code = app()->getLocale() ?: Language::ZH_CN;
        $language_id = Language::mapCodeToId($language_code);

        $customer_categories = $customer->categoriesIsShowLatestPriority($language_id, true)
            ->where('has_asset', Category::HAS_ASSET)
            ->values();

        return $customer_categories;
    }

    /**
     * @param $customer_id
     * @throws \App\Exceptions\ApiAbstractException
     *
     * @return Customer
     */
    private function checkIsNotVirtualCustomer($customer_id)
    {
        /** @var Customer $customer */
        $customer = (new Customer)->where('provider_type', '<>', Customer::PROVIDER_TYPE_VIRTUAL)
            ->find($customer_id);

        $this->checkItemExist($customer);

        return $customer;
    }

    /**
     * 所有品牌 with 品牌系列
     *
     * @return Brand[]|Builder[]|Collection
     */
    private function getGroupBrandsWithBrandSeries()
    {
        /** @var Collection $providers */
        $providers = Customer::virtualProviders();
        $brands = (new Brand)->whereIn('customer_id', $providers->modelKeys())
            ->has('onShelfProducts')
            ->with('brandSeries', 'customer')
            ->get(['id', 'name', 'customer_id']);

        $group_brands = $brands->groupBy('customer_id')
            ->transform(function (Collection $customer_brands, int $customer_id) {
                $data = [
                    'customer_id'   => $customer_id,
                    'customer_name' => $customer_brands->first()->customer->name ?? null,
                    'brands'        => $customer_brands,
                ];

                $customer_brands->makeHidden('customer');

                return $data;
            })
            ->values();

        return $group_brands;
    }

    /**
     * @return Product[]|\Illuminate\Database\Eloquent\Builder[]|Collection|\Illuminate\Support\Collection
     */
    public function groupVirtualBrandsByCategory()
    {
        /** @var Collection $providers */
        $providers = Customer::virtualProviders();
        $virtual_products = (new Product)
            ->filterOnShelf()
            ->filterCustomersOwn($providers->modelKeys()) // 过滤出正常的虚拟供应商
            ->filterCategoryHasAsset(Category::HAS_ASSET)   // 过滤商品的类型：化妆品
            ->groupBy(['products.customer_id', 'brand_id', 'category_id'])
            ->with('brand.brandSeries', 'customer')
            ->select([
                'customer_id', 'brand_id', 'category_id'
            ])
            ->get();  // jd($virtual_products->groupBy( ['category_id','customer_id'], $preserveKeys = true));

        return $virtual_products->groupBy(['category_id', 'customer_id'], $preserveKeys = true)
            ->map(function (Collection $group_products_by_category, $category_id) {
                $group_products_by_customer = $group_products_by_category->map(function (Collection $group_products_by_customer, $customer_id) use ($category_id) {

                    return [
                        'customer_id'   => $customer_id,
                        'customer_name' => $group_products_by_customer->first()->customer->name ?? null,
                        'brands'        => $group_products_by_customer->pluck('brand')->unique()->values(),
                    ];
                })->values();

                return [
                    'category_id'     => $category_id,
                    'customer_brands' => $group_products_by_customer,
                ];
            })->values();
    }

    /**
     * @param Collection $customer_categories
     * @param $group_brands_with_series
     * @return Collection
     */
    private function groupCategoriesByBrandsWithSeries(Collection $customer_categories, $group_brands_with_series)
    {
        $customer_categories->transform(function (Category $customer_category) use ($group_brands_with_series) {

            $customer_category->customer_brands = $this->getBrands($group_brands_with_series, $customer_category->id);

            return $customer_category;
        });

        return $customer_categories;
    }

    /**
     * @param BaseCollection $group_brands
     * @param $category_id
     * @return null
     */
    private function getBrands(BaseCollection $group_brands, $category_id)
    {
        $group_brands = $group_brands->where('category_id', $category_id)->first();

        return $group_brands['customer_brands'] ?? null;
    }

    /**
     * foreach 遍历 group_customer_categories的数据
     * 重新拼装、格式化筛选 brands / brand_series的数据
     *
     * @param $group_customer_categories
     * @return array
     */
    private function foreachAssembleData(Collection $group_customer_categories): array
    {
        $products = $this->getGroupCustomerCategoriesProducts($group_customer_categories);

        $data = [];
        foreach ($group_customer_categories as $group_customer_category) {

            $customers_brands = null;

            foreach ($group_customer_category->customer_brands ?? collect([]) as $customer_brand) {

                $brands = [];

                foreach ($customer_brand['brands'] as $brand) {
                    $brand_series = [];

                    foreach ($brand->brandSeries as $series) {
                        $brand_series[] = [
                            "id"          => $series->id,
                            "customer_id" => $series->customer_id,
                            "brand_id"    => $series->brand_id,
                            "name"        => $series->name,
                            "image"       => $series->image,
                            "sort"        => $series->sort,
                            'category_id' => $group_customer_category->id,
                        ];
                    }

                    $brand_series_ids = $products
                        ->where('customer_id', $brand->customer_id)
                        ->where('category_id', $group_customer_category->id)
                        ->where('brand_id', $brand->id)
                        ->pluck('brand_series_id')->unique()->values();

                    $brands[] = [
                        "id"           => $brand->id,
                        "customer_id"  => $brand->customer_id,
                        "url"          => $brand->url,
                        "name"         => $brand->name,
                        "logo"         => $brand->logo,
                        "locked"       => $brand->locked,
                        "sort"         => $brand->sort,
                        'category_id'  => $group_customer_category->id,
                        "brand_series" => collect($brand_series)->whereIn('id', $brand_series_ids)->values(),
                    ];
                }

                $brand_ids = $products
                    ->where('category_id', $group_customer_category->id)
                    ->where('customer_id', $customer_brand['customer_id'])
                    ->pluck('brand_id')
                    ->unique()->values();

                $customers_brands[] = [
                    "customer_id"   => $customer_brand['customer_id'],
                    "customer_name" => $customer_brand['customer_name'],
                    "brands"        => collect($brands)->whereIn('id', $brand_ids)->values(),
                ];
            }

            $data[] = [
                'id'              => $group_customer_category->id,
                'has_asset'       => $group_customer_category->has_asset,
                'name'            => $group_customer_category->name,
                'customer_brands' => $customers_brands,
            ];
        }
        return $data;
    }

    /**
     * @param Collection $group_customer_categories
     * @return Product[]|Collection
     */
    private function getGroupCustomerCategoriesProducts(Collection $group_customer_categories)
    {
        $cate_ids = $group_customer_categories->filter(function ($group_customer_category) {
            return $group_customer_category->customer_brands !== null;
        })->pluck('id');

        $customer_ids = $group_customer_categories[0]->customer_brands->pluck('customer_id');

        $products = (new Product)
            ->whereIn('category_id', $cate_ids)
            ->whereIn('customer_id', $customer_ids)
            ->select(
                'category_id',
                'customer_id',
                'brand_id',
                'brand_series_id'
            )
            ->get();
        return $products;
    }

}
